using System;
using System.Web;
using System.Xml;

namespace Demo.SharePoint.Utilities
{
    public class GoogleGeocoder
    {
        const string BASE_URL = "http://maps.google.com/maps/geo?";

        /// <summary>
        /// Initializes a new instance of the <see cref="GoogleGeocoder"/> class.
        /// </summary>
        /// <param name="key">The key.</param>
        public GoogleGeocoder(string key)
        {
            Key = key;
        }

        /// <summary>
        /// Geocodes the specified street address.
        /// </summary>
        /// <param name="streetAddress1">The street address 1.</param>
        /// <param name="streetAddress2">The street address 2.</param>
        /// <param name="city">The city.</param>
        /// <param name="state">The state.</param>
        /// <param name="zip">The zip.</param>
        /// <param name="latitude">The latitude.</param>
        /// <param name="longitude">The longitude.</param>
        /// <returns></returns>
        public void Geocode(string streetAddress1, string streetAddress2, string city, string state, string zip, out double latitude, out double longitude)
        {
            string url = BASE_URL + "q=" + HttpUtility.UrlEncode(streetAddress1 + "," + streetAddress2 + "," + city + "," + state + "," + zip) + "&output=xml&key=" + Key;
            XmlDocument document = new XmlDocument();
            document.Load(url);

            XmlNamespaceManager namespaceManager = new XmlNamespaceManager(document.NameTable);
            namespaceManager.AddNamespace("g", "http://earth.google.com/kml/2.0");

            XmlNode status = document.SelectSingleNode("/g:kml/g:Response/g:Status/g:code", namespaceManager);
            if (status.InnerText != "200")
                throw new Exception("Google returned a status of " + status.InnerText);

            XmlNode coordinates = document.SelectSingleNode("/g:kml/g:Response/g:Placemark/g:Point/g:coordinates", namespaceManager);
            if (coordinates == null)
                throw new Exception("Coordinates are null");

            string[] csv = coordinates.InnerText.Split(new[] { ',' });
            longitude = double.Parse(csv[0]);
            latitude = double.Parse(csv[1]);
        }

        /// <summary>
        /// Geocodes the specified street address.
        /// </summary>
        /// <param name="streetAddress1">The street address 1.</param>
        /// <param name="city">The city.</param>
        /// <param name="state">The state.</param>
        /// <param name="zip">The zip.</param>
        /// <param name="latitude">The latitude.</param>
        /// <param name="longitude">The longitude.</param>
        /// <returns></returns>
        public void Geocode(string streetAddress1, string city, string state, string zip, out double latitude, out double longitude)
        {
            string url = BASE_URL + "q=" + HttpUtility.UrlEncode(streetAddress1 + "," + city + "," + state + "," + zip) + "&output=xml&key=" + Key;
            XmlDocument document = new XmlDocument();
            document.Load(url);

            XmlNamespaceManager namespaceManager = new XmlNamespaceManager(document.NameTable);
            namespaceManager.AddNamespace("g", "http://earth.google.com/kml/2.0");

            XmlNode status = document.SelectSingleNode("/g:kml/g:Response/g:Status/g:code", namespaceManager);
            if (status.InnerText != "200")
                throw new Exception("Google returned a status of " + status.InnerText);

            XmlNode coordinates = document.SelectSingleNode("/g:kml/g:Response/g:Placemark/g:Point/g:coordinates", namespaceManager);
            if (coordinates == null)
                throw new Exception("Coordinates are null");

            string[] csv = coordinates.InnerText.Split(new[] { ',' });
            longitude = double.Parse(csv[0]);
            latitude = double.Parse(csv[1]);
        }

        /// <summary>
        /// Gets or sets the google api key.
        /// </summary>
        /// <value>The key.</value>
        private string Key { get; set; }
    }
}